﻿using Bot.Domain.Enum;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;

namespace Bot.Domain.Report
{
    public class ChatSourceItem : BaseReportInfoItem
    {
        public double chatCount { get; set; }
        public double chatPercentage { get; set; }
        public double fromAutoInvitationCount { get; set; }
        public double fromAutoInvitationPercentage { get; set; }
        public double fromChatButtonCount { get; set; }
        public double fromChatButtonPercentage { get; set; }
        public double fromManuallyInvitationCount { get; set; }
        public double fromManuallyInvitationPercentage { get; set; }
    }
    public class ChatSourceInfo : BaseReportInfo<ChatSourceItem>
    {
        public double totalChatCount { get; set; }
        public double totalFromAutoInvitationCount { get; set; }
        public double totalFromChatButtonCount { get; set; }
        public double totalFromManuallyInvitationCount { get; set; }
    }

    //data
    public class ChatSourceEntity
    {
        public ChatSourceEntity() { }

        public System.DateTime RequestTime { get; set; }
        public EnumLiveChatSource Source { get; set; }
    }
    public class ChatSourceEntityInfo
    {
        public List<ChatSourceEntity> ChatSourceEntityList { get; set; }
        public List<ChatSourceNumEntity> ChatSourceNumEntityList { get; set; }

    }
    public class ChatSourceNumEntity
    {
        public int AutoInvitations { get; set; }
        public int ChatButtons { get; set; }
        public int Chats { get; set; }
        public int FieldId { get; set; }
        public string FieldName { get; set; }
        public int ManuallyInvitations { get; set; }
    }

    public class ChatSourceWrap : BasicWrap<ChatSourceItem, ChatSourceInfo, ChatSourceEntityInfo>
    {
        public static ChatSourceInfo GetChatSource(SearchCriteria search, bool ifEncode = true)
        {
            //System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            //watch.Start();

            //ChatSourceEntityInfo entityInfo = ChatSourceProcess.GetChatSourceData(search); //数据库查询出来的数据
            ChatSourceEntityInfo entityInfo = null; //数据库查询出来的数据

            //System.Diagnostics.Debug.WriteLine("Access Time: " + watch.Elapsed);
            //watch.Reset();
            //watch.Start();
            //System.Diagnostics.Debug.WriteLine(entityInfo.ChatSourceEntityList.Count);
            //System.Diagnostics.Debug.WriteLine(entityInfo.ChatSourceNumEntityList.Count);

            ChatSourceInfo result = new ChatSourceInfo();
            //UTCToLocal(ref entityInfo);
            switch (search.dimensionType)
            {
                case EnumDimensionType.ByTime://by time
                    result = GetInfoByTime(search, entityInfo, PushByTimeData, PushByTimeDataWith24_7Distribution, PushByTimeDataWith48HalfHourDistribution);
                    break;
                case EnumDimensionType.ByDepartment://by department
                case EnumDimensionType.RequestPage:
                    result = GetChatSourceByDimension(search, entityInfo, ifEncode);
                    break;
            }

            //watch.Stop();
            //System.Diagnostics.Debug.WriteLine("Calc Time: " + watch.Elapsed);

            return result;
        }

        //search the chat Source info for campaign by criteria
        private static ChatSourceInfo GetChatSourceByDimension(SearchCriteria search, ChatSourceEntityInfo entityInfo, bool ifEncode)
        {
            var result = new ChatSourceInfo();
            result.dataType = EnumReportDataType.DataByDimension;
            List<ChatSourceNumEntity> data = entityInfo.ChatSourceNumEntityList;

            result.totalChatCount = data.Sum(i => i.Chats);
            if (search.dimensionType == EnumDimensionType.ByDepartment)
            {
                result.totalFromChatButtonCount = data.Sum(i => i.ChatButtons);
                result.totalFromManuallyInvitationCount = data.Sum(i => i.ManuallyInvitations);
                result.totalFromAutoInvitationCount = data.Sum(i => i.AutoInvitations);
            }

            result.dataList = new List<ChatSourceItem>();

            foreach (var item in data)
            {
                var newItem = new ChatSourceItem();
                newItem.tableRowName = GetTableRowName(ifEncode, item.FieldName);
                newItem.fieldId = item.FieldId;
                newItem.chatCount = item.Chats;
                newItem.chatPercentage = CalcPercent(item.Chats, result.totalChatCount);
                if (search.dimensionType == EnumDimensionType.ByDepartment)
                {
                    newItem.fromChatButtonCount = item.ChatButtons;
                    newItem.fromChatButtonPercentage = CalcPercent(item.ChatButtons, result.totalFromChatButtonCount);
                    newItem.fromManuallyInvitationCount = item.ManuallyInvitations;
                    newItem.fromManuallyInvitationPercentage = CalcPercent(item.ManuallyInvitations, result.totalFromManuallyInvitationCount);
                    newItem.fromAutoInvitationCount = item.AutoInvitations;
                    newItem.fromAutoInvitationPercentage = CalcPercent(item.AutoInvitations, result.totalFromAutoInvitationCount);
                }

                newItem.startTime = search.startDate.ToString();
                newItem.startTimeDate = search.startDate;
                newItem.endTime = search.endDate.ToString();
                newItem.endTimeDate = search.endDate;
                result.dataList.Add(newItem);
            }

            result.dataList = result.dataList.Reverse().ToList();
            return result;
        }

        private static ChatSourceInfo PushByTimeData(ChatSourceInfo result, ChatSourceEntityInfo entityInfo, SearchCriteria search)
        {
            IEnumerable<ChatSourceEntity> ChatSourceEntityList = entityInfo.ChatSourceEntityList.OrderBy(c => c.RequestTime);
            int lindex = 0;
            foreach (var item in ChatSourceEntityList)
            {
                item.RequestTime = DateTimeHelper.UTCToLocal(item.RequestTime);
                ChatSourceItem chatitem = result.dataList[lindex];
                while (item.RequestTime >= chatitem.endTimeDate && lindex < result.dataList.Count)
                {
                    lindex++;
                    chatitem = result.dataList[lindex];
                }
                chatitem.chatCount++;
                result.totalChatCount++;
                switch (item.Source)
                {
                    case EnumLiveChatSource.ChatButton:
                        chatitem.fromChatButtonCount++;
                        result.totalFromChatButtonCount++;
                        break;
                    case EnumLiveChatSource.AutoInvitation:
                        chatitem.fromAutoInvitationCount++;
                        result.totalFromAutoInvitationCount++;
                        break;
                    case EnumLiveChatSource.ManuallyInvitation:
                        chatitem.fromManuallyInvitationCount++;
                        result.totalFromManuallyInvitationCount++;
                        break;
                    default:
                        break;
                }
            }
            GetListTotal(ref result, search);
            return result;
        }

        private static ChatSourceInfo PushByTimeDataWith24_7Distribution(ChatSourceInfo result, ChatSourceEntityInfo entityInfo, SearchCriteria search)
        {
            int[] numDays = CountDays(search.startDate, search.endDate);
            foreach (ChatSourceEntity chat in entityInfo.ChatSourceEntityList)
            {
                DateTime requestTimeLocal = DateTimeHelper.UTCToLocal(chat.RequestTime);
                int index = (int)requestTimeLocal.DayOfWeek * hournum + requestTimeLocal.Hour;

                result.dataList[index].chatCount++;
                result.totalChatCount++;
                switch (chat.Source)
                {
                    case EnumLiveChatSource.ChatButton:
                        result.dataList[index].fromChatButtonCount++;
                        result.totalFromChatButtonCount++;
                        break;
                    case EnumLiveChatSource.ManuallyInvitation:
                        result.dataList[index].fromManuallyInvitationCount++;
                        result.totalFromManuallyInvitationCount++;
                        break;
                    case EnumLiveChatSource.AutoInvitation:
                        result.dataList[index].fromAutoInvitationCount++;
                        result.totalFromAutoInvitationCount++;
                        break;
                    default:
                        break;
                }
            }

            foreach (ChatSourceItem item in result.dataList)
            {
                int num = numDays[item.IndexNum / hournum];
                if (num > 0)
                {
                    item.chatCount = CalcAvg(item.chatCount, num);
                    item.fromChatButtonCount = CalcAvg(item.fromChatButtonCount, num);
                    item.fromManuallyInvitationCount = CalcAvg(item.fromManuallyInvitationCount, num);
                    item.fromAutoInvitationCount = CalcAvg(item.fromAutoInvitationCount, num);
                }
                else
                {
                    item.chatCount = 0;
                    item.fromChatButtonCount = 0;
                    item.fromManuallyInvitationCount = 0;
                    item.fromAutoInvitationCount = 0;
                }
                result.dataByTimeWithDistribution[item.IndexNum / hournum].dataByTimeList.Add(item);
            }
            result.dataList = new List<ChatSourceItem>();
            GetListTotal(ref result, search);
            return result;
        }

        private static ChatSourceInfo PushByTimeDataWith48HalfHourDistribution(ChatSourceInfo result, ChatSourceEntityInfo entityInfo, SearchCriteria search)
        {
            int dayNum = GetDays(search.startDate, search.endDate);

            foreach (ChatSourceEntity chat in entityInfo.ChatSourceEntityList)
            {
                DateTime requestTimeLocal = DateTimeHelper.UTCToLocal(chat.RequestTime);
                int index = requestTimeLocal.Hour * 2 + (requestTimeLocal.Minute < 30 ? 0 : 1);

                result.dataList[index].chatCount++;
                result.totalChatCount++;
                switch (chat.Source)
                {
                    case EnumLiveChatSource.ChatButton:
                        result.dataList[index].fromChatButtonCount++;
                        result.totalFromChatButtonCount++;
                        break;
                    case EnumLiveChatSource.ManuallyInvitation:
                        result.dataList[index].fromManuallyInvitationCount++;
                        result.totalFromManuallyInvitationCount++;
                        break;
                    case EnumLiveChatSource.AutoInvitation:
                        result.dataList[index].fromAutoInvitationCount++;
                        result.totalFromAutoInvitationCount++;
                        break;
                    default:
                        break;
                }

            }

            foreach (ChatSourceItem item in result.dataList)
            {
                if (dayNum > 0)
                {
                    item.chatCount = CalcAvg(item.chatCount, dayNum);
                    item.fromChatButtonCount = CalcAvg(item.fromChatButtonCount, dayNum);
                    item.fromManuallyInvitationCount = CalcAvg(item.fromManuallyInvitationCount, dayNum);
                    item.fromAutoInvitationCount = CalcAvg(item.fromAutoInvitationCount, dayNum);
                }
                else
                {
                    item.chatCount = 0;
                    item.fromChatButtonCount = 0;
                    item.fromManuallyInvitationCount = 0;
                    item.fromAutoInvitationCount = 0;
                }
            }

            GetListTotal(ref result, search);

            return result;
        }

        private static void GetListTotal(ref ChatSourceInfo result, SearchCriteria search)
        {
            double divNum = 0;
            if (search.timeUnit == EnumTimeIntervalType.Distribution24_7Hour)
            {
                divNum = GetWeeksInDateRange(search.startDate, search.endDate);
            }
            else if (search.timeUnit == EnumTimeIntervalType.Distribution48HalfHour)
            {
                divNum = GetDays(search.startDate, search.endDate);
            }
            else
            {
                result.totalChatCount = CalcTwoPoint(result.totalChatCount);
                result.totalFromChatButtonCount = CalcTwoPoint(result.totalFromChatButtonCount);
                result.totalFromManuallyInvitationCount = CalcTwoPoint(result.totalFromManuallyInvitationCount);
                result.totalFromAutoInvitationCount = CalcTwoPoint(result.totalFromAutoInvitationCount);
            }

            if (search.timeUnit == EnumTimeIntervalType.Distribution24_7Hour || search.timeUnit == EnumTimeIntervalType.Distribution48HalfHour)
            {
                result.totalChatCount = CalcAvg(result.totalChatCount, divNum);
                result.totalFromChatButtonCount = CalcAvg(result.totalFromChatButtonCount, divNum);
                result.totalFromManuallyInvitationCount = CalcAvg(result.totalFromManuallyInvitationCount, divNum);
                result.totalFromAutoInvitationCount = CalcAvg(result.totalFromAutoInvitationCount, divNum);
            }
        }

        #region export

        //search the New Export CSV Data for Chat Source Info by criteria
        public static NewExportCSVData GetExprotData(SearchCriteria search)
        {
            ChatSourceInfo info = GetChatSource(search, false);
            NewExportCSVData result = new NewExportCSVData(string.Empty, new List<NewCSVColumn>(), new DataTable());
            switch (search.dimensionType)
            {
                case EnumDimensionType.ByTime://by time
                case EnumDimensionType.ByDepartment://by department
                    {
                        result = GetExprotCSVData(search, info, info.FieldList);
                        break;
                    }
                case EnumDimensionType.RequestPage:
                    {
                        result = GetExprotCSVData(search, info, new List<string>() { info.FieldList[0] });
                        break;
                    }
            }
            return result;
        }


        #endregion

    }
}
